#ifndef _movinteral_h_
#define _movinteral_h_

#include <stdint.h>
#include <stddef.h>



/*---------------------------------------------------------------------------
-----------------------------box---------------------------------------------
---------------------------------------------------------------------------*/
// basic box  -------  header + data（就是各种box）   
//   header == type + size;
struct mov_box_t
{
	uint64_t size; // 用来指定box的大小  0-size: box扩展到文件尾, 1-size: 会有一个 8 B 的large size字段来存放大小
	uint32_t type;
#if defined(DEBUG) || defined(_DEBUG)
	int level;
#endif
};
/*---------------------------------------------------------------------------
----------------------------atom---------------------------------------------
---------------------------------------------------------------------------*/

#define N_BRAND	8

struct mov_ftyp_t
{
	uint32_t major_brand;     // 为了解决兼容性问题，一般使用 isom;代表主商标
	uint32_t minor_version;   // 指定最低兼容版本；商标版本号

	uint32_t compatible_brands[N_BRAND];   // 通常指MP4中的额外格式；用于兼容其他版本号
	int brands_count;     // 额外格式数目
}; 


// A.4 Temporal structure of the media (p148)
//视频和每个轨道都有一个时间刻度。  
//这定义了一个时间轴，它具有每秒滴答数  
// 一般每一个box中的子box中的第一个box都是一个header box  ，并且一般都是一个 full box ; 用来描述 media 的相关信息
struct mov_mvhd_t
{
	// FullBox
	uint32_t version : 8;   // box 版本  一般是 0
	uint32_t flags : 24;    //  根据各个Box类型定义是0还是1

	uint32_t timescale;    // 文件媒体在1秒时间内的刻度值，可以理解为1秒长度的时间单元数，这个只用来计算了该Mp4文件的长度，但是没有参与PTS和DTS的计算。
	uint64_t duration;     // 播放时长，该值除以time scale字段即可以得到该影片的总时长单位秒s
	uint64_t creation_time; // 创建时间  相对于UTC时间1904-01-01零点的秒数
	uint64_t modification_time; // 修改时间   相对于UTC时间1904-01-01零点的秒数 

	uint32_t rate;    // 推荐播放速率，高16位和低16位分别为小数点整数部分和小数部分   该值为1.0（0x00010000）表示正常前向播放
	uint16_t volume; // 与Rate类似，[8.8] 格式，1.0（0x0100）表示最大音量 
	//uint16_t reserved;    // 保留位
	//uint32_t reserved2[2];
	int32_t matrix[9]; // u,v,w   // 视频变换矩阵，实际填写都是默认值，一般不关心这个字段
	//int32_t pre_defined[6];     // 预览相关的信息，一般都是填充0，
	uint32_t next_track_ID;    //  下一个Track使用的id号，通过该值减去1可以判断当前文件的Track数量
};

enum
{
	MOV_TKHD_FLAG_TRACK_ENABLE = 0x01,
	MOV_TKHD_FLAG_TRACK_IN_MOVIE = 0x02,
	MOV_TKHD_FLAG_TRACK_IN_PREVIEW = 0x04,
};

struct mov_tkhd_t
{
	// FullBox
	uint32_t version : 8;    // box 版本  一般是 0
	uint32_t flags : 24;    //  根据各个Box类型定义是0还是1

	uint32_t track_ID; // 唯一标识该Track的一个非零值
	uint64_t creation_time; // 创建时间  相对于UTC时间1904-01-01零点的秒数
	uint64_t modification_time; // 修改时间   相对于UTC时间1904-01-01零点的秒数
	uint64_t duration; // 播放时长，该值除以time scale字段即可以得到该影片的总时长单位秒s
	//uint32_t reserved;

	//uint32_t reserved2[2];
	int16_t layer;     // 视频层，值小的在上层
	int16_t alternate_group;   // track分组信息，一般默认为0，表示该track和其它track没有建立群组关系
	int16_t volume; // 播放此track的音量，1.0为正常音量
	//uint16_t reserved;	  // 保留位
	int32_t matrix[9]; // u,v,w   视频变换矩阵
	uint32_t width; //如果该Track为Video Track，则表示图像的宽度 （16.16浮点表示）
	uint32_t height; // 如果该Track为Video Track，则表示图像的高度（16.16浮点表示）
};

struct mov_mdhd_t
{
	// FullBox
	uint32_t version : 8;
	uint32_t flags : 24;

	uint32_t timescale; // 当前Track的时间计算单位；也就是时基
	uint64_t duration; //  该Track的播放时长，需要参考前面的timescale计算
	uint64_t creation_time; // 当前Track创建时间（相对于UTC时间1904-01-01零点的秒数）
	uint64_t modification_time; // 当前Track修改时间（相对于UTC时间1904-01-01零点的秒数）

	uint32_t pad : 1;
	uint32_t language : 15;  // 媒体语言码，  参考其他标准
	uint32_t pre_defined : 16;
};
// 用来记录 data stream中的 sample 的 描述信息；其实就是记录解码参数；其他的box如果需要里面的数据进行封装的话；可以在此结构体提取；避免重复数据
struct mov_sample_entry_t
{
    uint16_t data_reference_index; // ref [dref] 数据参考 box
    uint8_t object_type_indication; // H.264/AAC 解码配置描述
    uint8_t stream_type; // MP4 stream 类型
	uint8_t* extra_data; // H.264 sps/pps 
	int extra_data_size;    

    union
    {
        struct mov_bitrate_t
        {
            uint32_t bufferSizeDB;
            uint32_t maxBitrate;
            uint32_t avgBitrate;
        } bitrate;    // 码率

        //struct mov_uri_t
        //{
        //	char uri[256];
        //} uri;
        // visual
        struct mov_visual_sample_t    // 
        {
            uint16_t width;
            uint16_t height;
            uint32_t horizresolution; // 0x00480000 - 72dpi
            uint32_t vertresolution; // 0x00480000 - 72dpi
            uint16_t frame_count; // default 1
            uint16_t depth; // 0x0018

			struct mov_pixel_aspect_ratio_t    // 像素的宽高比
			{
				uint32_t h_spacing;
				uint32_t v_spacing;
			} pasp;
        } visual;

        struct mov_audio_sample_t   // 音频信息
        {
            uint16_t channelcount; // 音频通道    一般默认双通道
            uint16_t samplesize; // 默认 16
            uint32_t samplerate; // 默认采样率 << 16
        } audio;
    } u;
};

// 下面的几个box是最关键的box ；它们都是Stbl box 的子box； 
// 建立 Sample-Trunk-Track 三者之间的关系； 将Sample和时间进行映射
// 采样描述容器
struct mov_stsd_t
{
    struct mov_sample_entry_t *current;  // curr sample 的 描述信息, read only
    struct mov_sample_entry_t *entries;  // sample 描述信息 
    uint32_t entry_count;    // sample 描述信息的个数
};
//采样时间容器  通过这个表格，可以找到任何时间的sample。
// sample number和解码时间DTS之间的映射表
struct mov_stts_t
{
	uint32_t sample_count;  // 连续相同时间长度sample delta的sample个数
	uint32_t sample_delta; // 在媒体的时间尺度上    每个sample delta 即以timescale为单位的时间长度。
};
//Chunk采样容器 
//说明那些Sample可以划分为一个Trunk。
struct mov_stsc_t
{
	uint32_t first_chunk;          // 每一个 entry 开始的 chunk 位置
	uint32_t samples_per_chunk;    // 每一个 chunk 里面包含多少的 sample
	uint32_t sample_description_index;   // 每一个 sample 的描述。一般可以默认设置为 1。
};
// 使某个track时间戳偏移，达到延迟播放的效果
struct mov_elst_t
{
	uint64_t segment_duration; //  表示该edit段的时长    segment_duration/ timescale = 真实秒数 
	int64_t media_time;        //  表示该edit段的起始时间 
	int16_t media_rate_integer;   //  edit段的速率  整数部分
	int16_t media_rate_fraction;  //  edit段的速率  小数部分
};
// 用来给 fMP4 的 sample 设置默认值；普通的MP4不需要他
struct mov_trex_t
{
//	uint32_t track_ID;
	uint32_t default_sample_description_index;   //每一个 sample 的描述。一般可以默认设置为 1。
	uint32_t default_sample_duration;
	uint32_t default_sample_size;
	uint32_t default_sample_flags; 
};
// tfhd 主要是对指定的 trak 进行相关的默认设置。
// 例如：sample 的时长，大小，偏移量等。不过，这些都可以忽略不设，只要你在其它 box 里面设置完整即可：
struct mov_tfhd_t
{
	uint32_t flags;
//	uint32_t track_ID;
	uint64_t base_data_offset;   // 是用来计算后面数据偏移量用到的
	uint32_t sample_description_index;  // sample  每一个 sample 的描述。一般可以默认设置为 1。
	uint32_t default_sample_duration;   // sample时长
	uint32_t default_sample_size;       // sample大小
	uint32_t default_sample_flags;
};




struct mov_udta_meta_t
{
	//char* title;
	//char* artist;
	//char* album_artist;
	//char* album;
	//char* date;
	//char* comment;
	//char* genre;
	//char* copyright;
	//char* lyrics;
	//char* description;
	//char* synopsis;
	//char* show;
	//char* episode_id;
	//char* network;
	//char* keywords;
	//char* season_num;
	//char* media_type;
	//char* hd_video;
	//char* gapless_playback;
	//char* compilation;

	uint8_t* cover; // 覆盖二进制数据, 只是 jpeg/png ----- 封面贴图的
	int cover_size; // 以字节表示的二进制数据长度
};
int mov_udta_meta_write(const struct mov_udta_meta_t* meta, void* data, int bytes);



/*---------------------------------------------------------------------------
-------------------------------buffer----------------------------------------
---------------------------------------------------------------------------*/
// 用于连接数据和文件的
struct mov_buffer_t
{
	// 读取媒体文件数据
	int (*read)(void* param, void* data, uint64_t bytes);
	// 写媒体文件数据
	int (*write)(void* param, const void* data, uint64_t bytes);
	// 设置偏移量
	int (*seek)(void* param, int64_t offset);
	// 获取偏移量
	int64_t (*tell)(void* param);
};


/*---------------------------------------------------------------------------
----------------------读写用户的参数到box缓存区的-------------------------------
---------------------------------------------------------------------------*/

struct mov_ioutil_t
{
	struct mov_buffer_t io;   // 文件操作接口
	void* param;     // 和文件较近的参数
	int error;       // 用于记录数据写入是否正确
};


static inline int mov_buffer_error(const struct mov_ioutil_t* io)
{
	return io->error;
}

static inline uint64_t mov_buffer_tell(const struct mov_ioutil_t* io)
{
	int64_t v;
	v = io->io.tell(io->param);  // 获取缓存区偏移
	if (v < 0)
		((struct mov_ioutil_t*)io)->error = -1;
	return v;
}

static inline void mov_buffer_seek(const struct mov_ioutil_t* io, int64_t offset)
{
//	if (0 == io->error)
	((struct mov_ioutil_t*)io)->error = io->io.seek(io->param, offset);   // 
}

static inline void mov_buffer_skip(struct mov_ioutil_t* io, uint64_t bytes)
{
	uint64_t offset;
	if (0 == io->error)
	{
		offset = io->io.tell(io->param);
		io->error = io->io.seek(io->param, offset + bytes);
	}
}


static inline void mov_buffer_read(struct mov_ioutil_t* io, void* data, uint64_t bytes)
{
	if (0 == io->error)
		io->error = io->io.read(io->param, data, bytes);
}

static inline void mov_buffer_write(const struct mov_ioutil_t* io, const void* data, uint64_t bytes)
{
	if (0 == io->error)
		((struct mov_ioutil_t*)io)->error = io->io.write(io->param, data, bytes);    // 将 data 上的 数据 写到 para 缓存区 中；其实就是写到了文件中
}

static inline uint8_t mov_buffer_r8(struct mov_ioutil_t* io)
{
	uint8_t v = 0;
	mov_buffer_read(io, &v, 1);
	return v;
}

static inline uint16_t mov_buffer_r16(struct mov_ioutil_t* io)
{
	uint16_t v;
	v = mov_buffer_r8(io);
	v = (v << 8) | mov_buffer_r8(io);
	return v;
}

static inline uint32_t mov_buffer_r24(struct mov_ioutil_t* io)
{
	uint32_t v;
	v = mov_buffer_r8(io);
	v = (v << 16) | mov_buffer_r16(io);
	return v;
}

static inline uint32_t mov_buffer_r32(struct mov_ioutil_t* io)
{
	uint32_t v;
	v = mov_buffer_r16(io);
	v = (v << 16) | mov_buffer_r16(io);
	return v;
}

static inline uint64_t mov_buffer_r64(struct mov_ioutil_t* io)
{
	uint64_t v;
	v = mov_buffer_r32(io);
	v = (v << 32) | mov_buffer_r32(io);
	return v;
}

static inline void mov_buffer_w8(const struct mov_ioutil_t* io, uint8_t v)
{
	mov_buffer_write(io, &v, 1);
}

static inline void mov_buffer_w16(const struct mov_ioutil_t* io, uint16_t v)
{
	mov_buffer_w8(io, (uint8_t)(v >> 8));
	mov_buffer_w8(io, (uint8_t)v);
}

static inline void mov_buffer_w24(const struct mov_ioutil_t* io, uint32_t v)
{
	mov_buffer_w16(io, (uint16_t)(v >> 8));
	mov_buffer_w8(io, (uint8_t)v);
}

static inline void mov_buffer_w32(const struct mov_ioutil_t* io, uint32_t v)
{
	mov_buffer_w16(io, (uint16_t)(v >> 16));
	mov_buffer_w16(io, (uint16_t)v);
}

static inline void mov_buffer_w64(const struct mov_ioutil_t* io, uint64_t v)
{
	mov_buffer_w32(io, (uint32_t)(v >> 32));
	mov_buffer_w32(io, (uint32_t)v);
}

/*---------------------------------------------------------------------------
----------------------------format--------------------------------------
---------------------------------------------------------------------------*/

#define MOV_OBJECT_TEXT		0x08 // Text Stream
#define MOV_OBJECT_MP4V		0x20 // Visual ISO/IEC 14496-2 (c)
#define MOV_OBJECT_H264		0x21 // Visual ITU-T Recommendation H.264 | ISO/IEC 14496-10
#define MOV_OBJECT_H265		0x23 // Visual ISO/IEC 23008-2 | ITU-T Recommendation H.265
#define MOV_OBJECT_AAC		0x40 // Audio ISO/IEC 14496-3
#define MOV_OBJECT_MP2V		0x60 // Visual ISO/IEC 13818-2 Simple Profile
#define MOV_OBJECT_AAC_MAIN	0x66 // MPEG-2 AAC Main
#define MOV_OBJECT_AAC_LOW	0x67 // MPEG-2 AAC Low
#define MOV_OBJECT_AAC_SSR	0x68 // MPEG-2 AAC SSR
#define MOV_OBJECT_MP3		0x69 // Audio ISO/IEC 13818-3
#define MOV_OBJECT_MP1V		0x6A // Visual ISO/IEC 11172-2
#define MOV_OBJECT_MP1A		0x6B // Audio ISO/IEC 11172-3
#define MOV_OBJECT_JPEG		0x6C // Visual ISO/IEC 10918-1 (JPEG)
#define MOV_OBJECT_PNG		0x6D // Portable Network Graphics (f)
#define MOV_OBJECT_JPEG2000	0x6E // Visual ISO/IEC 15444-1 (JPEG 2000)
#define MOV_OBJECT_VC1      0xA3 // SMPTE VC-1 Video
#define MOV_OBJECT_DIRAC    0xA4 // Dirac Video Coder
#define MOV_OBJECT_AC3      0xA5 // AC-3
#define MOV_OBJECT_EAC3     0xA5 // Enhanced AC-3
#define MOV_OBJECT_G719		0xA8 // ITU G.719 Audio
#define MOV_OBJECT_DTS      0xA9 // Core Substream
#define MOV_OBJECT_OPUS		0xAD // Opus audio
#define MOV_OBJECT_VP9      0xB1 // VP9 Video
#define MOV_OBJECT_FLAC     0xC1 // nonstandard from FFMPEG
#define MOV_OBJECT_VP8      0xC2 // nonstandard
#define MOV_OBJECT_G711a	0xFD // ITU G.711 alaw
#define MOV_OBJECT_G711u	0xFE // ITU G.711 ulaw
#define MOV_OBJECT_AV1		0xFF // AV1: 

#define MOV_OBJECT_NONE		0x00 // unknown object id
#define MOV_OBJECT_HEVC		MOV_OBJECT_H265
#define MOV_OBJECT_AVC		MOV_OBJECT_H264

/// MOV flags
#define MOV_FLAG_FASTSTART	0x00000001
#define MOV_FLAG_SEGMENT	0x00000002 // fmp4_writer only

/// MOV av stream flag
#define MOV_AV_FLAG_KEYFREAME 0x0001

/*---------------------------------------------------------------------------
-----------------------------------------------------------------------------
---------------------------------------------------------------------------*/

#define MOV_APP "ireader/media-xky"
#define MOV_TAG(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))



#define MOV_MOOV    MOV_TAG('m', 'o', 'o', 'v')
#define MOV_ROOT    MOV_TAG('r', 'o', 'o', 't')
#define MOV_TRAK    MOV_TAG('t', 'r', 'a', 'k')
#define MOV_MDIA    MOV_TAG('m', 'd', 'i', 'a')
#define MOV_EDTS    MOV_TAG('e', 'd', 't', 's')
#define MOV_MINF    MOV_TAG('m', 'i', 'n', 'f')
#define MOV_GMHD    MOV_TAG('g', 'm', 'h', 'd') 
#define MOV_DINF    MOV_TAG('d', 'i', 'n', 'f')
#define MOV_STBL    MOV_TAG('s', 't', 'b', 'l')
#define MOV_MVEX    MOV_TAG('m', 'v', 'e', 'x')
#define MOV_MOOF    MOV_TAG('m', 'o', 'o', 'f')
#define MOV_TRAF    MOV_TAG('t', 'r', 'a', 'f')
#define MOV_MFRA    MOV_TAG('m', 'f', 'r', 'a')

#define MOV_VIDEO	MOV_TAG('v', 'i', 'd', 'e') 
#define MOV_AUDIO	MOV_TAG('s', 'o', 'u', 'n') 
#define MOV_META	MOV_TAG('m', 'e', 't', 'a') 
#define MOV_HINT	MOV_TAG('h', 'i', 'n', 't') 
#define MOV_TEXT	MOV_TAG('t', 'e', 'x', 't') 
#define MOV_SUBT	MOV_TAG('s', 'u', 'b', 't')  
#define MOV_FONT	MOV_TAG('f', 'd', 's', 'm') 
#define MOV_CLCP	MOV_TAG('c', 'l', 'c', 'p') 
#define MOV_ALIS	MOV_TAG('a', 'l', 'i', 's') 
#define MOV_SBTL	MOV_TAG('s', 'b', 't', 'l') 

// 
#define MOV_H264    MOV_TAG('a', 'v', 'c', '1') 
#define MOV_HEVC    MOV_TAG('h', 'v', 'c', '1') 
#define MOV_MP4V    MOV_TAG('m', 'p', '4', 'v') 
#define MOV_MP4A    MOV_TAG('m', 'p', '4', 'a')
#define MOV_MP4S    MOV_TAG('m', 'p', '4', 's')
#define MOV_OPUS    MOV_TAG('O', 'p', 'u', 's')
#define MOV_VP8     MOV_TAG('v', 'p', '0', '8')
#define MOV_VP9     MOV_TAG('v', 'p', '0', '9') 
#define MOV_VP10    MOV_TAG('v', 'p', '1', '0')
#define MOV_AV1     MOV_TAG('a', 'v', '0', '1') 
#define MOV_VC1     MOV_TAG('v', 'c', '-', '1')
#define MOV_DIRAC   MOV_TAG('d', 'r', 'a', 'c')
#define MOV_AC3     MOV_TAG('a', 'c', '-', '3')
#define MOV_DTS     MOV_TAG('d', 't', 's', 'c')


enum
{
	MP4_STREAM_ODS		= 0x01, /* ObjectDescriptorStream */
	MP4_STREAM_CRS		= 0x02, /* ClockReferenceStream */
	MP4_STREAM_SDS		= 0x03, /* SceneDescriptionStream */
	MP4_STREAM_VISUAL	= 0x04, /* VisualStream */
	MP4_STREAM_AUDIO	= 0x05, /* AudioStream */
	MP4_STREAM_MP7		= 0x06, /* MPEG7Stream */
	MP4_STREAM_IPMP		= 0x07, /* IPMPStream */
	MP4_STREAM_OCIS		= 0x08, /* ObjectContentInfoStream */
	MP4_STREAM_MPEGJ	= 0x09, /* MPEGJStream */
	MP4_STREAM_IS		= 0x0A, /* Interaction Stream */
	MP4_STREAM_IPMPTOOL = 0x0B, /* IPMPToolStream */
};

enum
{
	MOV_BRAND_ISOM = MOV_TAG('i', 's', 'o', 'm'),
	MOV_BRAND_AVC1 = MOV_TAG('a', 'v', 'c', '1'),
	MOV_BRAND_ISO2 = MOV_TAG('i', 's', 'o', '2'),
	MOV_BRAND_MP71 = MOV_TAG('m', 'p', '7', '1'),
	MOV_BRAND_ISO3 = MOV_TAG('i', 's', 'o', '3'),
	MOV_BRAND_ISO4 = MOV_TAG('i', 's', 'o', '4'),
	MOV_BRAND_ISO5 = MOV_TAG('i', 's', 'o', '5'),
	MOV_BRAND_ISO6 = MOV_TAG('i', 's', 'o', '6'),
	MOV_BRAND_MP41 = MOV_TAG('m', 'p', '4', '1'), 
	MOV_BRAND_MP42 = MOV_TAG('m', 'p', '4', '2'),
	MOV_BRAND_MOV  = MOV_TAG('q', 't', ' ', ' '),
	MOV_BRAND_DASH = MOV_TAG('d', 'a', 's', 'h'),
	MOV_BRAND_MSDH = MOV_TAG('m', 's', 'd', 'h'),
	MOV_BRAND_MSIX = MOV_TAG('m', 's', 'i', 'x'),
};



// 最重要的一个容器了；记录着数据和chunk sample之间的时间映射关系
struct mov_stbl_t
{
	struct mov_stsc_t* stsc;    // stsc box 
	size_t stsc_count;          // stsc 个数
 
	uint64_t* stco;       // 记录chunk偏移 
	uint32_t stco_count;

	struct mov_stts_t* stts;      // 采样时间容器
	size_t stts_count;

	struct mov_stts_t* ctts;
	size_t ctts_count;

	uint32_t* stss; //  采样同步容器  sample 个数  开始为1
	size_t stss_count;
};
// sample 
struct mov_sample_t
{
	int flags;     //  音视频流标志
	int64_t pts;    // 播放时间戳
	int64_t dts;    // 解码时间戳

	void* data;    // sample 数据
	uint64_t offset; // 是一个32或64位整数，它给出其包含的媒体文件偏移量。  
	uint32_t bytes;  

	uint32_t sample_description_index;  // 每一个 sample 的描述。一般可以默认设置为 1。
	uint32_t samples_per_chunk; // write only 每一个 chunk 里面包含多少的 sample
	uint32_t first_chunk; // write only  每一个 entry 开始的 chunk 位置
};

struct mov_fragment_t
{
	uint64_t time;
	uint64_t offset; // moof 偏移
};
// trak包
struct mov_track_t
{
	uint32_t tag;               // 该trak是音频还是视频的标签  
	uint32_t handler_type;      //  记录该trak的类型，是音频还是视频
	const char* handler_descr;  // 视频 / 音频 / 字幕  处理程序
    // 下面都是该box下的子box
	struct mov_tkhd_t tkhd;
	struct mov_mdhd_t mdhd;
	struct mov_stbl_t stbl;

	// 8.8 Movie Fragments
	struct mov_trex_t trex;
	struct mov_tfhd_t tfhd;
	struct mov_fragment_t* frags;
	uint32_t frag_count, frag_capacity /*offset for read*/;

	struct mov_stsd_t stsd;

	struct mov_elst_t* elst;
	size_t elst_count;

	struct mov_sample_t* samples;    // 指向为 mov_sample_t 分配的那块内存的起始地址，用来存放每一帧数据的描述信息
	uint32_t sample_count;    // sample当前已经存储了多少帧的描述信息-------------个数
	size_t sample_offset;     // sample总共可以存储的大小-------------个数

    int64_t tfdt_dts; // tfdt base Media DecodeTime
    int64_t start_dts; // write fmp4 only
    uint64_t offset; // write only
    int64_t last_dts; // write fmp4 only
    int64_t turn_last_duration; // write fmp4 only

	unsigned int flags;
};
// ROOT box ；MP4 整个封装
struct mov_t
{
	struct mov_ioutil_t io;
	
	struct mov_ftyp_t ftyp;    /* 视频文件使用的编码格式、标准等， */

	struct mov_mvhd_t mvhd;  /* 对整个媒体文件所包含的媒体数据（包含 Video track 和 Audio Track 等）进行全面的描述；包括 创建和修改时间，默认音量、色域、时长等信息*/

	int flags;
	int header;
	uint32_t mfro;                  // mfro size
	uint64_t moof_offset;           // last moof offset(from file begin)
    uint64_t implicit_offset;

	struct mov_track_t* track;      // current stream
	struct mov_track_t* tracks;     // MP4中所有的track；音频信息写到音频的track中，视频信息写到视频相关的track中
	int track_count;    // trak box 个数，如果是音 + 视频进行封装成MP4，

	const void* udta;
	uint64_t udta_size;
};





#define MOV_TREX_FLAG_IS_LEADING_MASK					0x0C000000
#define MOV_TREX_FLAG_SAMPLE_DEPENDS_ON_MASK			0x03000000
#define MOV_TREX_FLAG_SAMPLE_IS_DEPENDED_ON_MASK		0x00C00000
#define MOV_TREX_FLAG_SAMPLE_HAS_REDUNDANCY_MASK		0x00300000
#define MOV_TREX_FLAG_SAMPLE_PADDING_VALUE_MASK			0x000E0000
#define MOV_TREX_FLAG_SAMPLE_IS_NO_SYNC_SAMPLE			0x00010000
#define MOV_TREX_FLAG_SAMPLE_DEGRADATION_PRIORITY_MASK	0x0000FFFF


#define MOV_TREX_FLAG_SAMPLE_DEPENDS_ON_I_PICTURE       0x02000000
#define MOV_TREX_FLAG_SAMPLE_DEPENDS_ON_NOT_I_PICTURE   0x01000000

#define MOV_TFHD_FLAG_BASE_DATA_OFFSET					0x00000001
#define MOV_TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX			0x00000002
#define MOV_TFHD_FLAG_DEFAULT_DURATION					0x00000008
#define MOV_TFHD_FLAG_DEFAULT_SIZE						0x00000010
#define MOV_TFHD_FLAG_DEFAULT_FLAGS						0x00000020
#define MOV_TFHD_FLAG_DURATION_IS_EMPTY					0x00010000
#define MOV_TFHD_FLAG_DEFAULT_BASE_IS_MOOF				0x00020000

#define MOV_TRUN_FLAG_DATA_OFFSET_PRESENT						0x0001
#define MOV_TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT				0x0004
#define MOV_TRUN_FLAG_SAMPLE_DURATION_PRESENT					0x0100
#define MOV_TRUN_FLAG_SAMPLE_SIZE_PRESENT						0x0200
#define MOV_TRUN_FLAG_SAMPLE_FLAGS_PRESENT						0x0400
#define MOV_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT	0x0800

#define MOV_TRACK_FLAG_CTTS_V1							0x0001 //ctts version 1
#define FREE(p) do { if(p) free(p); } while(0)
#define DIFF(a, b) ((a) > (b) ? ((a) - (b)) : ((b) - (a)))

int mov_reader_root(struct mov_t* mov);
int mov_reader_box(struct mov_t* mov, const struct mov_box_t* parent);
int mp4_read_extra(struct mov_t* mov, const struct mov_box_t* parent);

int mov_read_ftyp(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_mvhd(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_tkhd(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_hdlr(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_mdhd(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_vmhd(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_smhd(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_nmhd(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_esds(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_elst(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_stsd(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_stsz(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_stz2(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_stsc(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_stco(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_stts(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_ctts(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_cslg(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_stss(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_avcc(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_hvcc(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_av1c(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_vpcc(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_tx3g(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_trex(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_leva(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_tfhd(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_trun(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_tfra(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_sidx(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_mfhd(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_tfdt(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_mehd(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_dops(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_pasp(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_gmin(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_text(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_smdm(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_coll(struct mov_t* mov, const struct mov_box_t* box);
int mov_read_udta(struct mov_t* mov, const struct mov_box_t* box);

size_t mov_write_ftyp(const struct mov_t* mov);
size_t mov_write_mvhd(const struct mov_t* mov);
size_t mov_write_mdhd(const struct mov_t* mov);
size_t mov_write_tkhd(const struct mov_t* mov);
size_t mov_write_hdlr(const struct mov_t* mov);
size_t mov_write_vmhd(const struct mov_t* mov);
size_t mov_write_smhd(const struct mov_t* mov);
size_t mov_write_nmhd(const struct mov_t* mov);
size_t mov_write_sthd(const struct mov_t* mov);
size_t mov_write_dinf(const struct mov_t* mov);
size_t mov_write_dref(const struct mov_t* mov);
size_t mov_write_elst(const struct mov_t* mov);
size_t mov_write_stsd(const struct mov_t* mov);
size_t mov_write_stts(const struct mov_t* mov, uint32_t count);
size_t mov_write_ctts(const struct mov_t* mov, uint32_t count);
size_t mov_write_stco(const struct mov_t* mov, uint32_t count);
size_t mov_write_stss(const struct mov_t* mov);
size_t mov_write_stsc(const struct mov_t* mov);
size_t mov_write_stsz(const struct mov_t* mov);
size_t mov_write_esds(const struct mov_t* mov);
size_t mov_write_avcc(const struct mov_t* mov);
size_t mov_write_hvcc(const struct mov_t* mov);
size_t mov_write_av1c(const struct mov_t* mov);
size_t mov_write_vpcc(const struct mov_t* mov);
size_t mov_write_tx3g(const struct mov_t* mov);
size_t mov_write_trex(const struct mov_t* mov);
size_t mov_write_tfhd(const struct mov_t* mov);
size_t mov_write_trun(const struct mov_t* mov, uint32_t from, uint32_t count, uint32_t moof);
size_t mov_write_tfra(const struct mov_t* mov);
size_t mov_write_styp(const struct mov_t* mov);
size_t mov_write_tfdt(const struct mov_t* mov);
size_t mov_write_sidx(const struct mov_t* mov, uint64_t offset);
size_t mov_write_mfhd(const struct mov_t* mov, uint32_t fragment);
size_t mov_write_edts(const struct mov_t* mov);
size_t mov_write_stbl(const struct mov_t* mov);
size_t mov_write_minf(const struct mov_t* mov);
size_t mov_write_mdia(const struct mov_t* mov);
size_t mov_write_trak(const struct mov_t* mov);
size_t mov_write_dops(const struct mov_t* mov);
size_t mov_write_udta(const struct mov_t* mov);

uint32_t mov_build_stts(struct mov_track_t* track);
uint32_t mov_build_ctts(struct mov_track_t* track);
uint32_t mov_build_stco(struct mov_track_t* track);
void mov_apply_stco(struct mov_track_t* track);
void mov_apply_elst(struct mov_track_t *track);
void mov_apply_stts(struct mov_track_t* track);
void mov_apply_ctts(struct mov_track_t* track);
void mov_apply_stss(struct mov_track_t* track);
void mov_apply_elst_tfdt(struct mov_track_t *track);

void mov_write_size(const struct mov_t* mov, uint64_t offset, size_t size);

size_t mov_stco_size(const struct mov_track_t* track, uint64_t offset);

int mov_fragment_read_next_moof(struct mov_t* mov);
int mov_fragment_seek_read_mfra(struct mov_t* mov);
int mov_fragment_seek(struct mov_t* mov, int64_t* timestamp);

uint8_t mov_tag_to_object(uint32_t tag);
uint32_t mov_object_to_tag(uint8_t object);

void mov_free_track(struct mov_track_t* track);
struct mov_track_t* mov_add_track(struct mov_t* mov);
struct mov_track_t* mov_find_track(const struct mov_t* mov, uint32_t track);
struct mov_track_t* mov_fetch_track(struct mov_t* mov, uint32_t track); // find and add
int mov_add_audio(struct mov_track_t* track, const struct mov_mvhd_t* mvhd, uint32_t timescale, uint8_t object, int channel_count, int bits_per_sample, int sample_rate, const void* extra_data, size_t extra_data_size);
int mov_add_video(struct mov_track_t* track, const struct mov_mvhd_t* mvhd, uint32_t timescale, uint8_t object, int width, int height, const void* extra_data, size_t extra_data_size);
int mov_add_subtitle(struct mov_track_t* track, const struct mov_mvhd_t* mvhd, uint32_t timescale, uint8_t object, const void* extra_data, size_t extra_data_size);

#endif
